package org.colcon.web.model;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.colcon.web.model.framework.IContainer;
import org.colcon.web.model.framework.IItem;

public class Container extends Item implements IContainer
{
	private static final long serialVersionUID = 5883704263223287840L;

	private Map<String, IItem> children;
	
	public Container()
	{
		this(new HashMap<String, String>());
	}
	
	public Container(Map<String, String> args)
	{
		super(args);
	}
	
	public Container(String id)
	{
		this(null, id);
	}
	
	public Container(String parent, String id)
	{
		super(parent, id);
		
		children = new HashMap<String, IItem>();
	}
	
	public String getText()
	{
		return "container (" + children.size() + ")";
	}
	
	public String getPath()
	{
		if(isRoot())
			return getId();
		
		return super.getPath();
	}

	public boolean hasChild(String id)
	{
		return children.containsKey(id);
	}

	public IItem getChild(String id)
	{
		return children.get(id);
	}
	
	public boolean removeChild(String id)
	{
		if(!children.containsKey(id))
			return false;
		
		children.remove(id);
		
		return true;
	}
	
	/**
	 * <p>recurses through the container hierarchy following the given path</p>
	 * <p>path is relative to this container</p>
	 * 
	 * <p>example:</p>
	 * 
	 * <p>get("groups/groupName/laws/lawName")</p>
	 * 
	 * <p>is equivalent to</p>
	 * 
	 * <p>getChild("groups").getChild("groupName").getChild("laws").getChild("lawName")</p>
	 * 
	 * @param path
	 * @return item at given path
	 */
	public IItem get(String path)
	{
		if(path == null || path.length() == 0)
			return this;
		
		String[] array = path.split("/");
		
		if(array.length == 0)
			return this;
		
		IItem item;
		
		if(array[0].equals(getId()))
			item = this;
		else
			item = children.get(array[0]);
		
		for(int i = 1; i < array.length && item != null; i++)
		{
			if(item.isContainer())
				item = ((IContainer)item).getChild(array[i]);
			else
				return null;
		}
		
		return item;
	}
	
	public IItem get(String parent, String id)
	{
		return get(parent + '/' + id);
	}
	
	public boolean has(String path)
	{
		return get(path) != null;
	}
	
	public boolean has(String parent, String id)
	{
		return has(parent + '/' + id);
	}

	public boolean add(IItem item)
	{
		String id = item.getId();
		
		if(children.containsKey(id))
			return false;
		
		item.setParentPath(getPath());
		
		children.put(id, item);
		
		return true;
	}
	
	public boolean add(String parent, IItem item)
	{
		IItem p = get(parent);

		if(p == null || !p.isContainer())
			return false;
		
		return ((IContainer)p).add(item);
	}
	
	public boolean remove(String path)
	{
		if(path == null)
			return false;
		
		String[] array = path.split("/");
		
		if(array.length == 1)
			return removeChild(array[0]);
		
		String parent = array[1];
		
		for(int i = 1; i < array.length - 1; i++)
			parent += "/" + array[i];
		
		String id = array[array.length - 1];
		
		return remove(parent, id);
	}
	
	public boolean remove(String path, String id)
	{
		IItem item = get(path);
		
		if(item == null)
			return false;
		
		IItem parent = get(path);
		
		if(parent == null || !parent.isContainer())
			return false;
		
		return ((IContainer)parent).removeChild(item.getId());
	}
	
	public boolean addContainer(String id)
	{
		return add(new Container(getPath(), id));
	}
	
	public List<IItem> getChildren() 
	{
		return new LinkedList<IItem>(children.values());
	}
	
	public List<IItem> getGrandChildren(String child)
	{
		if(!has(child))
			return null;
		
		IItem item = get(child);
		
		if(!item.isContainer())
			return null;
		
		return ((IContainer)item).getChildren();
	}
}
